<script setup lang="ts">
/**
 * 基于SSE(Server-Sent Events)的日志流显示组件
 * 该组件演示了Vue前端如何通过EventSource API接收实时日志数据
 */
import { ref, onMounted, onUnmounted } from 'vue'
import axios from 'axios'

// 响应式数据定义
const logs = ref<Array<{timestamp: string, level: string, message: string, source: string}>>([])
const isConnected = ref(false)
const eventSource = ref<EventSource | null>(null)
const statusMessage = ref('未连接')
const autoScroll = ref(true)

/**
 * 连接到SSE日志流
 * 注意：更新API路径
 */
const connectToStream = () => {
  // 如果已经连接，则不重复连接
  if (isConnected.value) {
    return
  }

  try {
    // 创建EventSource连接到日志流端点 (使用更新后的API路径)
    eventSource.value = new EventSource('http://127.0.0.1:5000/api/logs/stream')

    // 监听消息事件
    eventSource.value.onmessage = (event) => {
      if (event.data) {
        try {
          // 解析接收到的JSON数据
          const logData = JSON.parse(event.data)

          // 如果是心跳包则忽略
          if (Object.keys(logData).length === 0) {
            return
          }

          // 添加新日志到列表末尾（最新的在后面）
          logs.value.push(logData)

          // 限制日志数量，避免内存占用过大
          if (logs.value.length > 100) {
            logs.value.shift()
          }

          // 如果启用自动滚动，滚动到最新日志
          if (autoScroll.value) {
            setTimeout(() => {
              const container = document.querySelector('.log-container')
              if (container) {
                container.scrollTop = container.scrollHeight
              }
            }, 0)
          }
        } catch (e) {
          // 如果不是JSON数据，可能是心跳包或其他信息
          console.log('Received non-JSON message:', event.data)
        }
      }
    }

    // 监听连接打开事件
    eventSource.value.onopen = () => {
      isConnected.value = true
      statusMessage.value = '已连接到日志流'
      console.log('Connected to log stream')
    }

    // 监听错误事件
    eventSource.value.onerror = (error) => {
      statusMessage.value = '连接错误'
      console.error('EventSource failed:', error)
      // 出错时断开连接
      isConnected.value = false
    }

  } catch (error) {
    statusMessage.value = '连接失败'
    console.error('Failed to create EventSource:', error)
  }
}

/**
 * 断开SSE日志流连接
 */
const disconnectFromStream = () => {
  if (eventSource.value) {
    eventSource.value.close()
    eventSource.value = null
    isConnected.value = false
    statusMessage.value = '已断开连接'
  }
}

/**
 * 清空日志列表
 */
const clearLogs = () => {
  logs.value = []
}

/**
 * 启动日志流生成器
 * 注意：更新API路径
 */
const startLogGenerator = async () => {
  try {
    const response = await axios.post('http://127.0.0.1:5000/api/logs/start')
    statusMessage.value = response.data.message
  } catch (error) {
    statusMessage.value = '启动日志生成器失败'
    console.error('Failed to start.py log generator:', error)
  }
}

/**
 * 停止日志流生成器
 * 注意：更新API路径
 */
const stopLogGenerator = async () => {
  try {
    const response = await axios.post('http://127.0.0.1:5000/api/logs/stop')
    statusMessage.value = response.data.message
  } catch (error) {
    statusMessage.value = '停止日志生成器失败'
    console.error('Failed to stop log generator:', error)
  }
}

/**
 * 获取日志流状态
 * 注意：更新API路径
 */
const getStreamStatus = async () => {
  try {
    const response = await axios.get('http://127.0.0.1:5000/api/logs/status')
    statusMessage.value = response.data.message
  } catch (error) {
    statusMessage.value = '获取状态失败'
    console.error('Failed to get stream status:', error)
  }
}

/**
 * 组件挂载时的操作
 */
onMounted(() => {
  // 组件挂载时自动连接到日志流
  connectToStream()
})

/**
 * 组件卸载时的操作
 */
onUnmounted(() => {
  // 组件卸载时断开连接
  disconnectFromStream()
})

/**
 * 根据日志级别获取CSS类名
 */
const getLogLevelClass = (level: string) => {
  switch (level.toLowerCase()) {
    case 'error':
      return 'log-error'
    case 'warn':
      return 'log-warn'
    case 'debug':
      return 'log-debug'
    default:
      return 'log-info'
  }
}
</script>

<template>
  <div class="log-streamer">
    <h2>SSE日志流演示</h2>

    <!-- 控制面板 -->
    <div class="controls">
      <button @click="connectToStream" :disabled="isConnected">连接</button>
      <button @click="disconnectFromStream" :disabled="!isConnected">断开</button>
      <button @click="startLogGenerator">启动生成器</button>
      <button @click="stopLogGenerator">停止生成器</button>
      <button @click="getStreamStatus">获取状态</button>
      <button @click="clearLogs">清空日志</button>

      <label class="auto-scroll">
        <input type="checkbox" v-model="autoScroll">
        自动滚动
      </label>
    </div>

    <!-- 状态显示 -->
    <div class="status">
      <p><strong>状态:</strong> {{ statusMessage }}</p>
    </div>

    <!-- 日志显示区域 -->
    <div class="log-container">
      <div
        v-for="(log, index) in logs"
        :key="index"
        :class="['log-entry', getLogLevelClass(log.level)]"
      >
        <span class="log-timestamp">[{{ log.timestamp }}]</span>
        <span class="log-level">[{{ log.level }}]</span>
        <span class="log-source">[{{ log.source }}]</span>
        <span class="log-message">{{ log.message }}</span>
      </div>

      <!-- 无日志时的提示 -->
      <div v-if="logs.length === 0" class="no-logs">
        暂无日志数据
      </div>
    </div>
  </div>
</template>

<style scoped>
.log-streamer {
  max-width: 1000px;
  margin: 0 auto;
  padding: 20px;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

.controls {
  margin-bottom: 20px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

.controls button {
  background-color: #4CAF50;
  border: none;
  color: white;
  padding: 8px 16px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 14px;
  cursor: pointer;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  transition: background-color 0.3s;
}

.controls button:hover {
  background-color: #45a049;
}

.controls button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.controls button:nth-child(3),
.controls button:nth-child(5) {
  background-color: #2196F3;
}

.controls button:nth-child(3):hover,
.controls button:nth-child(5):hover {
  background-color: #1976D2;
}

.controls button:nth-child(4) {
  background-color: #f44336;
}

.controls button:nth-child(4):hover {
  background-color: #d32f2f;
}

.controls button:nth-child(6) {
  background-color: #FF9800;
}

.controls button:nth-child(6):hover {
  background-color: #F57C00;
}

.auto-scroll {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-left: auto;
  font-size: 14px;
}

.status {
  margin-bottom: 20px;
  padding: 12px 15px;
  border: 1px solid #ddd;
  border-radius: 6px;
  background-color: #f8f9fa;
  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}

.log-container {
  height: 400px;
  overflow-y: auto;
  border: 1px solid #e1e5e9;
  border-radius: 6px;
  padding: 15px;
  background-color: #ffffff;
  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
  font-family: 'Consolas', 'Courier New', monospace;
  display: flex;
  flex-direction: column;
}

.log-entry {
  margin-bottom: 8px;
  padding: 10px 12px;
  border-radius: 4px;
  font-size: 13px;
  line-height: 1.5;
  border-left: 3px solid #e1e5e9;
  background-color: #f8f9fa;
  transition: all 0.2s ease;
}

.log-entry:hover {
  background-color: #e9ecef;
  transform: translateX(2px);
}

.log-entry:last-child {
  margin-bottom: 0;
}

.log-timestamp {
  color: #495057;
  margin-right: 10px;
  font-weight: 600;
}

.log-level {
  color: #007bff;
  margin-right: 10px;
  font-weight: bold;
  text-transform: uppercase;
  font-size: 11px;
  padding: 2px 6px;
  border-radius: 3px;
  background-color: rgba(0, 123, 255, 0.1);
}

.log-source {
  color: #28a745;
  margin-right: 10px;
  font-weight: 500;
}

.log-message {
  color: #212529;
}

.log-error {
  border-left-color: #dc3545;
  background-color: #fff5f5;
}

.log-error .log-level {
  color: #dc3545;
  background-color: rgba(220, 53, 69, 0.1);
}

.log-error:hover {
  background-color: #f8d7da;
}

.log-warn {
  border-left-color: #ffc107;
  background-color: #fffdf5;
}

.log-warn .log-level {
  color: #ffc107;
  background-color: rgba(255, 193, 7, 0.1);
}

.log-warn:hover {
  background-color: #fff3cd;
}

.log-debug {
  border-left-color: #6f42c1;
  background-color: #f9f7fd;
}

.log-debug .log-level {
  color: #6f42c1;
  background-color: rgba(111, 66, 193, 0.1);
}

.log-debug:hover {
  background-color: #e2d9f3;
}

.log-info {
  border-left-color: #17a2b8;
}

.log-info .log-level {
  color: #17a2b8;
  background-color: rgba(23, 162, 184, 0.1);
}

.no-logs {
  text-align: center;
  color: #6c757d;
  font-style: italic;
  padding: 80px 0;
  font-size: 16px;
}
</style>
